#!/usr/bin/env python
""" AnyBackup is a windows specific backup program to keep multiple volumes in sync with multiple volumes
    Copyright (C) 2011  Andrew Hopkinson

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Exported Classes:

    easyListCtrl -- a wrapper for ListCtrl which transparently gives the easy of use found in ListBox but with all the bells and whistles of ListCtrl
    """

import wx
import os
import DriveUtil
from enum import AEnums
from sql import SQLLite
import datetime


class easyListCtrl:
    DRIVE = 'drive'
    FILE = 'file'
    STRING = 'string'
    """ a wrapper for ListCtrl which transparently gives the ease of use found in ListBox but with all the bells and whistles of ListCtrl """
    def __init__(self,parent,id,fileUtil,mode=None,single=True):
        self.mapping = {}
        self.fileUtil = fileUtil
        self.count = 0
        self.mode = mode
        self.auto = False
        self.single = single
        self.r = SQLLite()
        if not mode:
            self.mode = self.STRING
        style = wx.LC_REPORT
        if self.single:
            style = style|wx.LC_SINGLE_SEL
        self.listCtrl = wx.ListCtrl(parent,id,wx.DefaultPosition,wx.DefaultSize,style)
        self.setMode(self.mode)
        self.listCtrl.Bind(wx.EVT_LIST_BEGIN_DRAG,self.startDrag)

    def startDrag(self,evt):
        data = wx.FileDataObject()
        files = self.GetSelectedData()
        if type(files) != list:
            files = [files]
        for file in files:
            if type(file) == dict:
                path = self.r.getFullPath(file)
                if path:
                    data.AddFile(path)
        if not data.GetFilenames():
            return
        dropSource = wx.DropSource(self.listCtrl)
        dropSource.SetData(data)
        res = dropSource.DoDragDrop(flags=wx.Drag_CopyOnly)
        
    def GetSelectedData(self):
        data = []
        selected = -1
        while True:
            selected = self.listCtrl.GetNextItem(selected,wx.LIST_NEXT_ALL,wx.LIST_STATE_SELECTED)
            if selected >= 0:
                selectedItem = self.listCtrl.GetItem(selected)
                if selectedItem and self.single:
                    return self.mapping[selectedItem.GetData()]
                else:
                    data.append(self.mapping[selectedItem.GetData()])
            else:
                break
        if self.single:
            return None
        else:
            return data

    def SetImageList(self,imageList,type):
        return self.listCtrl.SetImageList(imageList,type)
    
    def getWidth(self):
        width = 0
        for column in xrange(self.listCtrl.GetColumnCount()):
            width += self.listCtrl.GetColumnWidth(column)
        return width
    
    def getListCtrl(self):
        return self.listCtrl

    def getMode(self):
        return self.mode

    def setMode(self,mode):
        self.count = 0
        self.mapping = {}
        self.columns = 1
        columnNames = None
        hideColumns = None
        columnFormats = None
        self.mode = mode
        self.listCtrl.ClearAll()
        if mode == self.DRIVE:
            self.columns = 3
            columnNames = ['Name','Free','Total']
            hideColumns = False
            columnFormats = [wx.LIST_FORMAT_LEFT,wx.LIST_FORMAT_RIGHT,wx.LIST_FORMAT_RIGHT]
        elif mode == self.FILE:
            self.columns= 3
            columnNames = ['Name','Size','Modified Time']
            hideColumns = False
            columnFormats = [wx.LIST_FORMAT_LEFT,wx.LIST_FORMAT_RIGHT,wx.LIST_FORMAT_RIGHT]
        elif mode == self.STRING:
            hideColumns = True
        if hideColumns:
            self.listCtrl.SetSingleStyle(wx.LC_NO_HEADER,True)
        else:
            self.listCtrl.SetSingleStyle(wx.LC_NO_HEADER,False)
        for i in xrange(self.columns):
            try:
                name = columnNames[i]
            except:
                name = ''
            try:
                colFormat = columnFormats[i]
            except:
                colFormat = wx.LIST_FORMAT_LEFT
            self.listCtrl.InsertColumn(i,name,colFormat)


    def populateDrives(self,drives):
        driveObjs = DriveUtil.getDriveDictionary()
        for drive in drives:
            d = drive
            newItem = wx.ListItem()
            free = "%.2f" % (float(d[AEnums.FREESPACE])/float(1048576))
            total = "%.2f" % (float(d[AEnums.TOTALSPACE])/float(1048576))
            freeStr = str(free) + 'GB'
            totalStr = str(total) + 'GB'
            extra = {
                1 : freeStr,
                2 : totalStr,
            }
            newItem.SetText(d[AEnums.NAME])
            fullPerc = float(d[AEnums.FREESPACE]) * 100 / float(d[AEnums.TOTALSPACE])
            color = wx.GREEN
            if fullPerc <= 10:
                color = '#B40404'
            elif fullPerc <= 15:
                color = 'YELLOW'
            newItem.SetBackgroundColour(color)
            if self.r.isLocked(d) and d[AEnums.TYPE] == AEnums.BACKUP:
                newItem.SetImage(self.fileUtil.getLocked())
            elif driveObjs.has_key(d[AEnums.NAME]+d[AEnums.SERIAL]):
                newItem.SetImage(self.fileUtil.getConnected())
            else:
                newItem.SetImage(self.fileUtil.getDisconnected())
            if not d[AEnums.TYPE] == AEnums.BACKUP:
                newItem.SetFont(wx.Font(10,wx.DEFAULT,wx.NORMAL,wx.BOLD))
            self.InsertItem(newItem,drive,extra=extra)
        self.adjust()

    def populateStrings(self,strings):
        for string in strings:
            newItem = wx.ListItem()
            newItem.SetText(unicode(string).encode('UTF-16'))
            newItem.SetTextColour(wx.RED)
            newItem.SetImage(self.fileUtil.getError())
            self.InsertItem(newItem,None)
        self.adjust()

    def populateFiles(self,files,fileRef=None,showDirs=False):
        for file in files:
            newItem = wx.ListItem()
            if showDirs:
                try:
                    newItem.SetText(unicode(file[AEnums.PREFIX]+os.sep+file[AEnums.PATH]+os.sep+file[AEnums.NAME]).encode('utf-8'))
                except UnicodeEncodeError:
                    continue
            else:
                newItem.SetText(unicode(file[AEnums.NAME]).encode('utf-8'))
            newItem.SetImage(self.fileUtil.getIcon(file))
            if file[AEnums.DIR] == str(True):
                newItem.SetTextColour(wx.BLUE)
                self.InsertItem(newItem,file)
            else:
                size = "%.2f" % (float(file[AEnums.SIZE])/float(1024))
                sizeStr = str(size)
                sizeStr += 'MB'
                dateStr = datetime.datetime.fromtimestamp(
                            file[AEnums.MTIME]).strftime('%m-%d-%Y %H:%M:%S')
                extra = {}
                extra[1] = sizeStr
                extra[2] = dateStr
                self.InsertItem(newItem,data=file,extra=extra)

        if fileRef is not None:
            if AEnums.PARENT in fileRef:
                p = self.r.getFile(fileRef[AEnums.PARENT],fileRef[AEnums.SETNAME])
                newItem = wx.ListItem()
                newItem.SetText("..")
                newItem.SetImage(self.fileUtil.getIcon(p))
                newItem.SetTextColour(wx.BLUE)
                self.InsertItem(newItem,p)
        self.adjust()

    def setSelectedDrive(self,file):
        for i in range(0,self.listCtrl.GetItemCount()):
            ref = self.mapping[self.listCtrl.GetItem(i).GetData()]
            if ref.getName() == file.getVolName() and ref.GetSerial() == file.getSerial():
                self.listCtrl.SetItemState(i,wx.LIST_STATE_SELECTED,wx.LIST_STATE_SELECTED)
                self.auto=True
                return

    def setSelectedFiles(self,file):
        for i in range(0,self.listCtrl.GetItemCount()):
            ref = self.mapping[self.listCtrl.GetItem(i).GetData()]
            if ref.getName() == file.getName() and ref.getDir() == file.getDir():
                self.auto=True
                self.listCtrl.SetItemState(1,wx.LIST_STATE_SELECTED,wx.LIST_STATE_SELECTED)
                return

    def isAutoSelect(self):
        if self.auto:
            self.auto = False
            return True
        return False

    def DeleteAllItems(self):
        self.count = 0
        self.mapping = {}
        return self.listCtrl.DeleteAllItems()

    def GetNextItem(self,item,options):
        return self.listCtrl.GetNextItem(item,options)

    def InsertItem(self,item,data=None,extra=None):
        self.mapping[self.count]=data
        item.SetData(self.count)
        #item.SetColumn(0)
        id = item.GetId()
        self.count += 1
        result = self.listCtrl.InsertItem(item)
        if extra:
            for col in extra:
                self.listCtrl.SetStringItem(id,col,extra[col])
        return result

    def GetData(self,item):
        data = self.mapping[item.GetData()]
        return data

    def adjust(self):
        for i in xrange(self.columns):
            self.listCtrl.SetColumnWidth(i,wx.LIST_AUTOSIZE)

